package org.vacoor.nothing.misc.express.fedex;

import com.fedex.rate.stub.*;
import org.apache.axis.types.NonNegativeInteger;

import java.math.BigDecimal;
import java.util.Calendar;

/**
 * FedEx 费率计算
 *
 * @author vacoor
 */
public class FedExRateService extends FedExSupport {

    public void getRate() {
        RateRequest req = new RateRequest();

        // 授权, 客户端, 协议版本信息
        req.setWebAuthenticationDetail(new WebAuthenticationDetail(new WebAuthenticationCredential(getKey(), getPassword())));
        req.setClientDetail(new ClientDetail(getAccountNumber(), getMeterNumber(), getIntegratorId(), null, null));
        req.setTransactionDetail(new TransactionDetail("Rate Request", null));
        req.setVersion(new VersionId("crs", 16, 0, 0));

        // 发货信息
        RequestedShipment requestedShipment = new RequestedShipment();
        requestedShipment.setShipTimestamp(Calendar.getInstance());       // 立即发货
        requestedShipment.setDropoffType(DropoffType.REGULAR_PICKUP);   // 上门取件 ??

        /*
        if (!false/*getAllRatesFlag) {
        */
            requestedShipment.setServiceType(ServiceType.PRIORITY_OVERNIGHT);   // 优先级, 隔夜
        requestedShipment.setPackagingType(PackagingType.YOUR_PACKAGING);   // 包裹类型, 必须制定 ServiceType 才有效
        /*
        }
        */
        //


        // 发货人信息
        Party shipper = new Party();
        Address shipperAddress = new Address(); // Origin information
//        shipperAddress.setStreetLines(new String[]{"1 Shipper St"});
//        shipperAddress.setCity("Memphis");
//        shipperAddress.setStateOrProvinceCode("TN");
        shipperAddress.setPostalCode("38115");
        shipperAddress.setCountryCode("US");
        shipper.setAddress(shipperAddress);
        requestedShipment.setShipper(shipper);

        // 收货人信息
        Party recipient = new Party();
        Address recipientAddress = new Address(); // Destination information
        // recipientAddress.setStreetLines(new String[]{"1 Recipient St"});
        // recipientAddress.setCity("COLLIERVILLE");
        // recipientAddress.setStateOrProvinceCode("TN");
        recipientAddress.setPostalCode("38017");
        recipientAddress.setCountryCode("US");
        recipient.setAddress(recipientAddress);

        requestedShipment.setRecipient(recipient);

        // 支付信息
        Payment shippingChargesPayment = new Payment();
        shippingChargesPayment.setPaymentType(PaymentType.SENDER);  // 现在只支持发货人支付
        requestedShipment.setShippingChargesPayment(shippingChargesPayment);

        // 包裹信息
        RequestedPackageLineItem rp = new RequestedPackageLineItem();
        rp.setGroupPackageCount(new NonNegativeInteger("1"));
        rp.setWeight(new Weight(WeightUnits.LB, new BigDecimal(15.0))); // 重量, LB -- pounds
        // 保险
//        rp.setInsuredValue(new Money("USD", new BigDecimal("100.00")));
        // 尺寸 IN -- 英寸
        rp.setDimensions(new Dimensions(new NonNegativeInteger("1"), new NonNegativeInteger("1"), new NonNegativeInteger("1"), LinearUnits.CM));

        // 特殊服务
        PackageSpecialServicesRequested pssr = new PackageSpecialServicesRequested();
        rp.setSpecialServicesRequested(pssr);

        requestedShipment.setRequestedPackageLineItems(new RequestedPackageLineItem[]{rp});

        requestedShipment.setPackageCount(new NonNegativeInteger("1")); // 包裹数
        req.setRequestedShipment(requestedShipment);

        //
        try {
            // Initialize the service
            RateServiceLocator service;
            RatePortType port;
            //
            service = new RateServiceLocator();
//            updateEndPoint(service);
            port = service.getRateServicePort();
            // This is the call to the web service passing in decode RateRequest and returning decode RateReply
            RateReply reply = port.getRates(req); // Service call
            if (isResponseOk(reply.getHighestSeverity())) {
                writeServiceOutput(reply);
                RateReplyDetail[] details = reply.getRateReplyDetails();
                for (RateReplyDetail detail : details) {
                    RatedShipmentDetail[] rsDetails = detail.getRatedShipmentDetails();
                    for (RatedShipmentDetail rsDetail : rsDetails) {
                        ShipmentRateDetail srDetail = rsDetail.getShipmentRateDetail();
                        Weight totalWeight = srDetail.getTotalBillingWeight();  // 订单总重
                        // srDetail.getTotalBaseCharge();
                    }
                }
            } else {
                printNotifications(reply.getNotifications());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /* ***********************
     *      Helper Method
     * ***********************/
    private static boolean isResponseOk(NotificationSeverityType notificationSeverityType) {
        if (notificationSeverityType == null) {
            return false;
        }

        if (notificationSeverityType.equals(NotificationSeverityType.WARNING) ||
                notificationSeverityType.equals(NotificationSeverityType.NOTE) ||
                notificationSeverityType.equals(NotificationSeverityType.SUCCESS)) {
            return true;
        }
        return false;
    }

    public static void writeServiceOutput(RateReply reply) {
        RateReplyDetail[] rrds = reply.getRateReplyDetails();
        for (int i = 0; i < rrds.length; i++) {
            RateReplyDetail rrd = rrds[i];
            //print("\nService type", rrd.getServiceType());
            print("Packaging type", rrd.getPackagingType());
            //print("Delivery DOW", rrd.getDeliveryDayOfWeek());
            // DayOfWeekType deliveryDayOfWeek = rrd.getDeliveryDayOfWeek();

            /*- 交付时间
            int month = rrd.getDeliveryTimestamp().get(Calendar.MONTH)+1;
            int date = rrd.getDeliveryTimestamp().get(Calendar.DAY_OF_MONTH);
            int year = rrd.getDeliveryTimestamp().get(Calendar.YEAR);
            String delDate = new String(month + "/" + date + "/" + year);
            print("Delivery date", delDate);
            print("Calendar DOW", rrd.getDeliveryTimestamp().get(Calendar.DAY_OF_WEEK));
            */

            RatedShipmentDetail[] rsds = rrd.getRatedShipmentDetails();
            for (int j = 0; j < rsds.length; j++) {
                print("RatedShipmentDetail " + j, "");
                RatedShipmentDetail rsd = rsds[j];
                ShipmentRateDetail srd = rsd.getShipmentRateDetail();
                print("  Rate type", srd.getRateType());
                printWeight("  Total Billing weight", srd.getTotalBillingWeight()); //
                printMoney("  Total surcharges", srd.getTotalSurcharges()); // 总附加费
                printMoney("  Total net charge", srd.getTotalNetCharge());  // 总费用

                // 包裹费用详情
                RatedPackageDetail[] rpds = rsd.getRatedPackages();
                if (rpds != null && rpds.length > 0) {
                    print("  RatedPackageDetails", "");
                    for (int k = 0; k < rpds.length; k++) {
                        print("  RatedPackageDetail " + i, "");
                        RatedPackageDetail rpd = rpds[k];
                        PackageRateDetail prd = rpd.getPackageRateDetail();
                        if (prd != null) {
                            printWeight("    Billing weight", prd.getBillingWeight());
                            printMoney("    Base charge", prd.getBaseCharge()); // 基本费用
                            Surcharge[] surcharges = prd.getSurcharges();       // 附加费用
                            if (surcharges != null && surcharges.length > 0) {
                                for (int m = 0; m < surcharges.length; m++) {
                                    Surcharge surcharge = surcharges[m];
                                    printMoney("    " + surcharge.getDescription() + " surcharge", surcharge.getAmount());
                                }
                            }
                        }
                    }
                }
            }
            System.out.println("");
        }
    }

    private static void printNotifications(Notification[] notifications) {
        System.out.println("Notifications:");
        if (notifications == null || notifications.length == 0) {
            System.out.println("  No notifications returned");
        }
        for (int i = 0; i < notifications.length; i++) {
            Notification n = notifications[i];
            System.out.print("  Notification no. " + i + ": ");
            if (n == null) {
                System.out.println("null");
                continue;
            } else {
                System.out.println("");
            }
            NotificationSeverityType nst = n.getSeverity();

            System.out.println("    Severity: " + (nst == null ? "null" : nst.getValue()));
            System.out.println("    Code: " + n.getCode());
            System.out.println("    Message: " + n.getMessage());
            System.out.println("    Source: " + n.getSource());
        }
    }

    private static void print(String msg, Object obj) {
        if (msg == null || obj == null) {
            return;
        }
        System.out.println(msg + ": " + obj.toString());
    }

    private static void printMoney(String msg, Money money) {
        if (msg == null || money == null) {
            return;
        }
        System.out.println(msg + ": " + money.getAmount() + " " + money.getCurrency());
    }

    private static void printWeight(String msg, Weight weight) {
        if (msg == null || weight == null) {
            return;
        }
        System.out.println(msg + ": " + weight.getValue() + " " + weight.getUnits());
    }

}
